home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C++ / Snippets / OSA_Runner 1.0d0 / sources / Shell.cp < prev    next >
Encoding:
Text File  |  1995-10-20  |  13.1 KB  |  626 lines  |  [TEXT/CWIE]

  1. /*
  2. *    Shell.cp
  3. *
  4. *    OSA_Runner
  5. *    ^^^^^^^^^^
  6. *    Main shell for application
  7. *    © Andrew Nemeth (where applicable), Warrimoo Australia 1994, 1995
  8. *    aznemeng@zeta.org.au
  9. *
  10. *    File created:        3 Oct 95.
  11. *    Modified:            3, 18, 20 Oct 95.
  12. */
  13.  
  14. #include    "gConstDefines.h"                                //     Global #defines & const's
  15. #include    "gVariables.h"                                    //     Global variable defn & 'externs'
  16. #include    "stdHighLevelApple.h"                            //    Application High-Level AE
  17.  
  18. #include    "AZN_DBUG.H"                                    //    debugging utilites
  19. #include    "AZN_TRunOSA.h"                                //    run an AppleScript
  20.  
  21. #include     <AppleEvents.h>                                //    Mac high level AE
  22. #include    <AEObjects.h>                                    //    mac OSL constants
  23. #include    <LowMem.h>
  24. #include    <Gestalt.h>
  25. #include    <Balloons.h>                                    //    Access to System 7 help menu
  26. #include     <limits.h>                                    //    For LONG_MAX
  27.  
  28.  
  29. //    FILE DEFINES…
  30. //
  31.  
  32. //                                                        'stopMask' parameter in '::FlushEvents()'
  33. const short            kshZapEvents = 0;
  34.  
  35.  
  36. //    PROGRAM GLOBALS
  37. //
  38. struct myGlobalStruct     * gptrGlobalsRec = NULL;
  39.  
  40.  
  41. //    FILE GLOBALS
  42. //
  43. static     MenuHandle    ghMenus[ kMenusInBar ];
  44. static     Boolean        gboolUpdateMenus;
  45. static     RgnHandle        ghMouseRgn;
  46.  
  47. //    Globals used to “tune” the performance of MainEventLoop
  48. //    (assume we’ll be starting in the foreground)
  49.  
  50. static    unsigned long    gulgRunQuantum;
  51. static    unsigned long    gulgSleepQuantum;
  52.  
  53.  
  54.  
  55. //     FILE FUNCTIONS…
  56. //
  57. static void     toolBoxInit        ( void );
  58. static void    assignProgGlobals    ( void );
  59. static void    menuBarInit        ( void );
  60. static void    eventLoop            ( void );
  61. static void    doEvent            ( EventRecord * );
  62.  
  63. static void    doMouseDown        ( EventRecord * );
  64. static void     doMenuChoice        ( long );
  65. static void     doAppleChoice        ( short );
  66. static void    doFileChoice        ( short );
  67. static void    doOptionsChoice    ( short );
  68.  
  69. static void    doKeyPress        ( EventRecord * );
  70. static void    maintainMenus        ( Boolean );
  71. static void    quitNow            ( void );
  72.  
  73. static void    convertDescToStr    ( AEDesc *, StringPtr );
  74.  
  75.  
  76.  
  77. void        main( void )
  78. //
  79. {
  80.     OSErr        myErr;
  81.     long            lgFeature;
  82.     const long    klgGestaltMask = 1L;
  83.  
  84.  
  85.     toolBoxInit();
  86.  
  87.     INIT_DEBUG();
  88. //                                                        MUST be system 7!
  89.     myErr = ::Gestalt( gestaltSystemVersion, &lgFeature );
  90.     if ( myErr == noErr && ( lgFeature < 0x0700 ) ) 
  91.         ExitToShell();
  92. //                                                        check for scripting support
  93.     myErr = ::Gestalt( gestaltAppleEventsAttr, &lgFeature );
  94.     if ( ( noErr == myErr ) && ( lgFeature & ( klgGestaltMask << gestaltScriptingSupport ) ) )
  95.         NULL;
  96.     else
  97.         {
  98.         ::Alert( kresidALRT_AScript, NULL );
  99.         ::ExitToShell();
  100.         };
  101.  
  102.     assignProgGlobals();
  103.  
  104.     menuBarInit();
  105.  
  106.     eventLoop();    
  107. }
  108.  
  109.  
  110.  
  111. void         toolBoxInit( void )
  112. //
  113. //    Initialise toolbox and memory 
  114. //
  115. {
  116.     ::InitGraf( &qd.thePort );
  117.     ::InitFonts( );
  118.     ::FlushEvents( everyEvent, kshZapEvents );
  119.     ::InitWindows( );
  120.     ::TEInit( );
  121.     ::InitDialogs( 0L );
  122.     ::InitCursor( );
  123. //                                                        cut down on heap fragmentation
  124.     ::MaxApplZone( );
  125.     ::MoreMasters( );
  126.     ::MoreMasters( );
  127. //                                                        fire up high leve AE
  128.     highLevelEventInit();
  129. }
  130.  
  131.  
  132.  
  133. void        assignProgGlobals( void )
  134. //
  135. //    A single place to assign all
  136. //    program–wide globals
  137. //
  138. {
  139. //                                                        create global struct on heap
  140.     gptrGlobalsRec = (myGlobalStruct *)::NewPtrClear( sizeof( myGlobalStruct ) );
  141.  
  142.     //    Note on the above
  143.     //    Don't use 'gptrGlobalsRec = new struct myGlobalStruct;' !
  144.     //    Operator new in ANSI library allocates blocks of 
  145.     //    memory in 65532 byte slabs.  As this global will be 
  146.     //    hanging around for the entire program, it is
  147.     //    much more efficient to only allocate a ptr of
  148.     //    size 352 bytes (or so).
  149.     //
  150. //                                                        initialise global values
  151.     if ( gptrGlobalsRec )
  152.         {
  153.         gptrGlobalsRec->boolDone = FALSE;
  154.  
  155. //                                                        event 'tuning' globals
  156.         gptrGlobalsRec->foregroundRunQuantum = 0L;    
  157.         gptrGlobalsRec->foregroundSleepQuantum = GetCaretTime( );
  158.         gptrGlobalsRec->backgroundRunQuantum = 0L;
  159.         gptrGlobalsRec->backgroundSleepQuantum = LONG_MAX;
  160.         }
  161. }
  162.  
  163.  
  164. void         menuBarInit( void )
  165. //
  166. //    Install about menu and then
  167. //    zap all items in menubar
  168. //
  169. {
  170.     MenuHandle    hMenu = NULL;
  171.     Handle        hMenuBar = NULL;
  172.  
  173.  
  174.     hMenuBar = ::GetNewMBar( kMenuBar_ID );
  175.     ASSERT( hMenuBar != nil );
  176.     
  177.     ::SetMenuBar( hMenuBar );
  178. //                                                        assign Global MenuHandle Array
  179.     for ( short i = kAppleNdx, j = kMApple_ID; i < kMenusInBar ; i++, j++ )
  180.         {
  181.         ghMenus[ i ] = (MenuHandle)::GetMenu( j );
  182.         ASSERT( ghMenus[ i ] != nil );
  183.         }
  184. //                                                        insert 'About Application' into apple Menu
  185.     hMenu = ::GetMHandle( kMApple_ID );
  186.     ASSERT( hMenu != nil );
  187.  
  188.     ::AddResMenu( hMenu, 'DRVR' );
  189.  
  190.     ::DrawMenuBar( );
  191.     gboolUpdateMenus = FALSE;
  192. }
  193.  
  194.  
  195.  
  196. void         eventLoop( void )
  197. //
  198. //    Main event handling loop
  199. //
  200. {
  201.     EventRecord        erRec;
  202.     unsigned long        ulgCheckEvents = 0L;
  203.  
  204.  
  205.     gulgRunQuantum = gptrGlobalsRec->foregroundRunQuantum;
  206.     gulgSleepQuantum = gptrGlobalsRec->foregroundSleepQuantum;
  207.     ghMouseRgn = nil;
  208.     gboolUpdateMenus = TRUE;
  209.  
  210.     gptrGlobalsRec->boolDone = FALSE;
  211.  
  212.     while ( ! gptrGlobalsRec->boolDone )
  213.         {
  214.         if ( gulgRunQuantum == 0  || ( ::TickCount( ) > ulgCheckEvents ) )
  215.             {
  216.             ulgCheckEvents = ::TickCount() + gulgRunQuantum;
  217.             ::WaitNextEvent( everyEvent, &erRec, gulgSleepQuantum, ghMouseRgn );
  218.             doEvent( &erRec );
  219.             }
  220.         }
  221. //                                                        final tidy-up prior to exit
  222.     quitNow();
  223. }
  224.  
  225.  
  226.  
  227.  
  228. void         doEvent( EventRecord *ptrEventRec )
  229. //
  230. //    Events are first dealt with here
  231. //    Note: most of these events are processed
  232. //    in the individual dialogFilter procedures!
  233. //
  234. {
  235.     switch ( ptrEventRec->what )
  236.         {
  237. //                                                        null events
  238.         case nullEvent:
  239.             break;
  240. //                                                        see 'stdHighLevelApple.cp'
  241.         case kHighLevelEvent:
  242.             ::AEProcessAppleEvent( ptrEventRec );
  243.             break;
  244. //                                                        key press
  245.         case autoKey:
  246.         case keyDown:
  247.             doKeyPress( ptrEventRec );
  248.             break;
  249. //                                                        rat press
  250.         case mouseDown:
  251.             doMouseDown( ptrEventRec );
  252.             break;
  253. //                                                        not handled
  254.         case activateEvt:
  255.         case updateEvt:
  256.             break;
  257. //                                                        disc insertions
  258.         case diskEvt:
  259.             if ( ptrEventRec->message >> 16 )
  260.                 {
  261.                 static    Point    where = { 50, 50 };
  262.                 ::DIBadMount( where, ptrEventRec->message );
  263.                 }
  264.             break;
  265. //                                                        multi-finder foreground/ background
  266.         case    osEvt:
  267.             switch ( ( ptrEventRec->message & osEvtMessageMask ) >> 24 )
  268.                 {
  269.                 case    mouseMovedMessage:
  270.                     break;
  271.                     
  272.                 case    suspendResumeMessage:                    
  273.                     if ( ptrEventRec->message & resumeFlag )
  274.                         {
  275.                         ::SetCursor( &qd.arrow );
  276.  
  277.                         gulgRunQuantum = gptrGlobalsRec->foregroundRunQuantum;
  278.                         gulgSleepQuantum = gptrGlobalsRec->foregroundSleepQuantum;
  279.                         }
  280.                     else
  281.                         {
  282.                         gulgRunQuantum = gptrGlobalsRec->backgroundRunQuantum;
  283.                         gulgSleepQuantum = gptrGlobalsRec->backgroundSleepQuantum;
  284.                         }
  285.                     break;
  286.                 }
  287.             break;
  288.         }
  289. //                                                        update menus when there's an interesting event
  290.     if ( ptrEventRec->what != nullEvent && gboolUpdateMenus )
  291.         maintainMenus( TRUE );
  292. }
  293.  
  294.  
  295.  
  296. void         doMouseDown( EventRecord  *ptrEventRec )
  297. //
  298. //    Someone squeezed the rat…
  299. //
  300. {
  301.     WindowPtr        ptrWindow;
  302.     short        thePart;
  303.     long            lgMenuChoice;
  304.     
  305.  
  306.     thePart = ::FindWindow( ptrEventRec->where, &ptrWindow );
  307.     switch( thePart )
  308.         {
  309. //                                                        menu selected
  310.         case inMenuBar:
  311.             lgMenuChoice = ::MenuSelect( ptrEventRec->where );
  312.             doMenuChoice( lgMenuChoice );
  313.             break;
  314. //                                                        window dragged about - not handled
  315.         case inDrag:
  316.         case inContent:
  317.             break;
  318. //                                                        DA's
  319.         case inSysWindow:
  320.             ::SystemClick( ptrEventRec, ptrWindow );
  321.             gboolUpdateMenus = TRUE;
  322.             break;
  323.         }
  324. }
  325.  
  326.  
  327.  
  328. void         doMenuChoice( long lgMenuChoice )
  329. //
  330. //    Menu chosen
  331. //
  332. {
  333.     short        menu;
  334.     short        shMenuItem;
  335.     
  336.  
  337.     if ( lgMenuChoice != 0 )
  338.         {
  339. //                                                        Macros to break 4-byte value into 2 shorts
  340.         menu = HiWord( lgMenuChoice ); 
  341.         shMenuItem = LoWord( lgMenuChoice );
  342.             
  343.         switch( menu )
  344.             {
  345.             case kMApple_ID:
  346.                 doAppleChoice( shMenuItem );
  347.                 break;
  348.  
  349.             case kMFile_ID:
  350.                 doFileChoice( shMenuItem );
  351.                 break;
  352.  
  353.             case kMOptions_ID:
  354.                 doOptionsChoice( shMenuItem );
  355.                 break;
  356. //                                                        system 7 Help menu - not handled
  357.             case kHMHelpMenuID:
  358.                 break;
  359. //                                                        catch-all escape to quit application
  360.             default:
  361.                 quitNow( );
  362.                 break;
  363.             }
  364.         ::HiliteMenu( 0 );
  365.         }
  366. }
  367.  
  368.  
  369.  
  370. void         doAppleChoice( short shMenuItem )
  371. //
  372. //    'About Application' chosen or DA
  373. //
  374. {
  375.     MenuHandle    appleMenu = NULL;
  376.     Str255        accName = { kEmptyString };
  377.     short        accNumber;
  378.     
  379.  
  380.     switch ( shMenuItem )
  381.         {
  382.         case kM_About:
  383. //                                                        knockout highlight on apple menu
  384.             ::FlashMenuBar( kMApple_ID );
  385.             ::NoteAlert( kresidALRT_About, kNilFilterProc );
  386.             gboolUpdateMenus = TRUE;
  387.             break;
  388. //                                                        existing Apple Menus
  389.         default:
  390.             appleMenu = ::GetMHandle( kMApple_ID );
  391.             ::GetItem( appleMenu, shMenuItem, accName );
  392.             accNumber = ::OpenDeskAcc( accName );
  393.             gboolUpdateMenus = TRUE;
  394.             break;
  395.         }
  396. }
  397.  
  398.  
  399.  
  400. void        doFileChoice( short shMenuItem )
  401. //
  402. //    Parse 'File' menu choice
  403. //
  404. {
  405.     switch( shMenuItem )
  406.         {
  407. //                                                        signal ready for quit
  408.         case kM_Quit:
  409.         default:
  410.             gptrGlobalsRec->boolDone = TRUE;
  411.             break;
  412.         }
  413. }
  414.  
  415.  
  416.  
  417. void        doOptionsChoice( short shMenuItem )
  418. //
  419. //    Parse 'Options' menu choice
  420. //
  421. {
  422.     const AEEventClass        kaeclassSuite = 'MySR';
  423.     const AEEventID        kaesuiteKind_1 = 'FRST',
  424.                         kaesuiteKind_2 = 'SCND';
  425.  
  426.     TRunOSA                * ptrobjRunOSA = NULL;
  427.     AEDesc                aedescResult = { typeNull, NULL };
  428.     Str255                str255Result = { "\p" };
  429.     long                    lgSize = 0L;
  430.     FSSpec                fsspecScript = { 0, 0L, "\p" };
  431.     OSErr                myErr = noErr;
  432.  
  433.  
  434.     //    create AppleScript runner object
  435.  
  436.     ptrobjRunOSA = new TRunOSA();
  437.  
  438.     ASSERT( noErr == myErr );
  439.  
  440.     switch( shMenuItem )
  441.         {
  442.         //    Run the applescript embedded in the application's
  443.         //    fork - use AppleEvents to indicate which portion of
  444.         //    the script to execute, also no vars are sent.
  445.         //
  446.         case kM_ASRun_NoVar:
  447.  
  448.             ::SetCursor( *GetCursor( watchCursor ) );                        
  449.  
  450.             myErr = ptrobjRunOSA->loadScript();
  451.             ASSERT( noErr == myErr );
  452.  
  453.             ::SetCursor( &qd.arrow );
  454.  
  455.             //    N.B, loading a script will take some time, so it might be an idea
  456.             //    to do it during application startup whilst the user is distracted with 
  457.             //    the splash screen.
  458.  
  459.             myErr = ptrobjRunOSA->runScript( kaeclassSuite, kaesuiteKind_1 );
  460.  
  461.             break;
  462.  
  463.         //    Do the same but this time WITH vars
  464.         //
  465.         case kM_ASRun_WithVar:
  466.  
  467.             ::SetCursor( *GetCursor( watchCursor ) );                        
  468.  
  469.             myErr = ptrobjRunOSA->loadScript();
  470.             ASSERT( noErr == myErr );
  471.  
  472.             ::SetCursor( &qd.arrow );
  473.  
  474.             myErr = ptrobjRunOSA->runScript( kaeclassSuite, kaesuiteKind_2,
  475.                                         "\pHello cruel world - rsrc" );
  476.             break;
  477.  
  478.         //    Run an external appleScript file with vars
  479.         //
  480.         case kM_ASFileRun_WithVar:
  481.  
  482.             //    Grab compiled AppleScript file called
  483.             //    "Sample AppleScript" located in same folder
  484.             //    as application
  485.             //
  486.             myErr = ::FSMakeFSSpec ( 0, 0L, "\pSample AppleScript", &fsspecScript );
  487.             if ( noErr == myErr )
  488.                 {
  489.                 ::SetCursor( *GetCursor( watchCursor ) );                        
  490.     
  491.                 myErr = ptrobjRunOSA->loadScript( fsspecScript );
  492.                 ASSERT( noErr == myErr );
  493.     
  494.                 ::SetCursor( &qd.arrow );
  495.  
  496.                 myErr = ptrobjRunOSA->runScript( kaeclassSuite, kaesuiteKind_2,
  497.                                             "\pHello cruel world - AS_File" );
  498.                 }
  499.             break;
  500. //                                                        catch-all in case of stupidity!
  501.         default:
  502.             quitNow();
  503.             break;
  504.         }
  505. //                                                        display text result        
  506.     if ( noErr == myErr )
  507.         {
  508.         myErr = ptrobjRunOSA->getResultDesc( &aedescResult, &lgSize );
  509.         
  510.         if ( noErr == myErr )
  511.             {
  512.             convertDescToStr( &aedescResult, str255Result );
  513.             
  514.             ::ParamText( str255Result, "\p", "\p", "\p" );
  515.             ::NoteAlert( kresidALRT_ASResults, NULL );
  516.             }
  517.         }
  518.  
  519.     delete ptrobjRunOSA;
  520.  
  521.     gboolUpdateMenus = TRUE;
  522. }
  523.  
  524.  
  525. void            convertDescToStr ( AEDesc * ptraedescItem, StringPtr str255Item )
  526. //
  527. //    Given an AEDesc of type 'typeChar',
  528. //    extract the string as a Str255
  529. //
  530. {
  531.     Handle    hData = NULL;
  532.     long        lgSize;
  533.  
  534.  
  535.     ASSERT( NULL != ptraedescItem );
  536.     ASSERT( NULL != str255Item );
  537.  
  538.     str255Item[0] = 0;
  539.     hData = ptraedescItem->dataHandle;
  540.  
  541.     lgSize = ::GetHandleSize ( hData );    
  542.     lgSize = ( lgSize > 255 ) ? 255 : lgSize;
  543.     
  544.     ::HLock( hData );
  545.     ::BlockMoveData( *hData, &str255Item[1], lgSize );
  546.     ::HUnlock( hData );
  547.     
  548.     str255Item[0] = short( lgSize );
  549. }
  550.  
  551.  
  552.  
  553. void        doKeyPress( EventRecord *ptrEventRec  )
  554. //
  555. //    Respond to cmd-'' keypresses
  556. //
  557. {
  558.     register char        chCharPressed;
  559.  
  560.  
  561.     chCharPressed = ptrEventRec->message & charCodeMask;
  562.  
  563.     if ( ( ptrEventRec->modifiers & cmdKey ) != 0 )
  564.         {
  565. //                                                        quit now 'cmd-/' key press
  566.         if ( chCharPressed == '/' && ptrEventRec->modifiers & cmdKey )
  567.             quitNow( );
  568.         else
  569.             doMenuChoice( MenuKey( chCharPressed ) );
  570.         }
  571. }
  572.  
  573.  
  574.  
  575. void        maintainMenus( Boolean boolEnableAll )
  576. //
  577. //    Make sure menus reflect 
  578. //    current state of application
  579. //    If 'boolEnableAll' is FALSE, then menubar
  580. //    is deactivated
  581. //
  582. {
  583.     const short    kshDoForAll = 0;
  584.     short    i;
  585.  
  586.  
  587.     //    Enable/ disable all menu bar headings
  588.     //
  589.     for ( i = kAppleNdx; i < kMenusInBar ; i++ )
  590.         {
  591.         if ( boolEnableAll )
  592.             ::EnableItem( ghMenus[ i ], kshDoForAll );
  593.         else
  594.             ::DisableItem( ghMenus[ i ], kshDoForAll );
  595.         }
  596.  
  597. //                                                        enable/ disable individual items
  598.     if ( boolEnableAll )
  599.         {
  600. //                                                        always activate
  601.         ::EnableItem( ghMenus[ kFileNdx ], kM_Quit );
  602.  
  603.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_ASRun_NoVar );
  604.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_ASRun_WithVar );
  605.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_ASFileRun_WithVar );
  606. //                                                        wait for update!
  607.         ::InvalMenuBar( );
  608.         }
  609. //                                                        deactivate mbar NOW!
  610.     else
  611.         ::DrawMenuBar( );
  612.  
  613.     gboolUpdateMenus = FALSE;
  614. }
  615.  
  616.  
  617.  
  618. void        quitNow( void )
  619. //
  620. //    When the cmd—'/' is pressed,
  621. //    things to do before exit
  622. //
  623. {
  624.     gptrGlobalsRec->boolDone = TRUE;
  625. }
  626.